package com.example.recordingpen_datacollection.Utils.http;

/**
 * Created by 84243 on 2024/5/17
 */

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Copyright (year) Beijing Volcano Engine Technology Ltd.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

public class Sign2 {
    //密钥
    private static final String ACCESSKEYID = "AKLTN2JhODM4ZThjNjA4NDY0ZThhYzMxMTI2ZTVjM2I4ODI";
    private static final String SECRETACCESSKEY = "WXpKalpHTmxOelV5WVRBM05EVmxPVGs1WkdNMk1EYzBOekUzWTJZMFlXVQ==";

    //2592000
    private static final String DurationSeconds = "2592000";   //token有效时间  s(秒 ) 0-30d (天 ) 最大值（2592000s）
    private static final String ResourceIds = "ep-20240516011401-g68qw";   //资源的ID列表
    private static final String ResourceType = "endpoint";   //资源类型



    public static void main(String[] args) throws Exception {
        getApikey();

    }


    private static final BitSet URLENCODER = new BitSet(256);

    private static final String CONST_ENCODE = "0123456789ABCDEF";
    public static final Charset UTF_8 = StandardCharsets.UTF_8;

    private final String region;
    private final String service;
    private final String schema;
    private final String host;
    private final String path;
    private final String ak;
    private final String sk;

    static {
        int i;
        for (i = 97; i <= 122; ++i) {
            URLENCODER.set(i);
        }

        for (i = 65; i <= 90; ++i) {
            URLENCODER.set(i);
        }

        for (i = 48; i <= 57; ++i) {
            URLENCODER.set(i);
        }
        URLENCODER.set('-');
        URLENCODER.set('_');
        URLENCODER.set('.');
        URLENCODER.set('~');
    }

//    public static void main(String[] args) {
//        Sign.getApikey();
//        System.out.println("Hello, World!");
//    }

    public Sign2(String region, String service, String schema, String host, String path, String ak, String sk) {
        this.region = region;
        this.service = service;
        this.host = host;
        this.schema = schema;
        this.path = path;
        this.ak = ak;
        this.sk = sk;
    }

    //调用该方法生成apikey
    public static String getApikey() throws Exception {
        String AccessKeyID = ACCESSKEYID;
        String  SecretAccessKey  = SECRETACCESSKEY;
        // 请求地址
        String endpoint = "open.volcengineapi.com";
        String path = "/"; // 路径，不包含 Query// 请求接口信息
        String service = "ark";
        String region = "cn-beijing";
        String schema = "https";
        Sign2 sign = new Sign2(region, service, schema, endpoint, path, AccessKeyID, SecretAccessKey);

        String action = "GetApiKey";
        String version = "2024-01-01";

        Date date = new Date();
        HashMap<String, String> queryMap = new HashMap<>();


        String requestBody = "{\n" +
                "    \"ResourceType\": \""+ResourceType+"\",\n" +
                "    \"ResourceIds\": [\n" +
                "        \""+ResourceIds+"\"\n" +
                "    ],\n" +
                "    \"DurationSeconds\": "+DurationSeconds+"\n" +
                "}";
            String apiKey = sign.doRequest("POST", queryMap, requestBody.getBytes(), date, action, version);
            System.out.println("getApikey: " +apiKey);
            return apiKey;
    }

    public String doRequest(String method, Map<String, String> queryList, byte[] body,
                          Date date, String action, String version) throws Exception {
        if (body == null) {
            body = new byte[0];
        }
        String xContentSha256 = hashSHA256(body);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String xDate = sdf.format(date);
        String shortXDate = xDate.substring(0, 8);
        String contentType = "application/json";

        String signHeader = "host;x-date;x-content-sha256;content-type";


        SortedMap<String, String> realQueryList = new TreeMap<>(queryList);
        realQueryList.put("Action", action);
        realQueryList.put("Version", version);
        StringBuilder querySB = new StringBuilder();
        for (String key : realQueryList.keySet()) {
            querySB.append(signStringEncoder(key)).append("=").append(signStringEncoder(realQueryList.get(key))).append("&");
        }
        querySB.deleteCharAt(querySB.length() - 1);

        String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" +
                "host:" + host + "\n" +
                "x-date:" + xDate + "\n" +
                "x-content-sha256:" + xContentSha256 + "\n" +
                "content-type:" + contentType + "\n" +
                "\n" +
                signHeader + "\n" +
                xContentSha256;

//        System.out.println("CanonicalStringBuilder: \n"+canonicalStringBuilder);

        String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
        String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
        String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;

        byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, region, service);
        String signature = bytesToHexString(hmacSHA256(signKey, signString));


        URL url = new URL(schema + "://" + host + path + "?" + querySB);



        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(method);
        conn.setRequestProperty("Host", host);
        conn.setRequestProperty("X-Date", xDate);
        conn.setRequestProperty("X-Content-Sha256", xContentSha256);
        conn.setRequestProperty("Content-Type", contentType);
        conn.setRequestProperty("Authorization", "HMAC-SHA256" +
                " Credential=" + ak + "/" + credentialScope +
                ", SignedHeaders=" + signHeader +
                ", Signature=" + signature);
//        System.out.println("Authorization: \n"+"HMAC-SHA256" +
//                " Credential=" + ak + "/" + credentialScope +
//                ", SignedHeaders=" + signHeader +
//                ", Signature=" + signature);
        if (!Objects.equals(conn.getRequestMethod(), "GET")) {
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            os.write(body);
            os.flush();
            os.close();
        }
        conn.connect();

        int responseCode = conn.getResponseCode();

        InputStream is;
        if (responseCode == 200) {
            is = conn.getInputStream();
        } else {
            is = conn.getErrorStream();
        }
//        is = conn.getInputStream();
        //通过InputStreamReader将字节流转换成字符串，在通过BufferedReader将字符流转换成自带缓冲流
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        String line = null;
        //按行读取
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        String response= sb.toString();

        is.close();
//        System.out.println("doRequest: " + response);
        return response;
    }
    /**
     * doRequest: {"ResponseMetadata":{"RequestId":"2024052009420209A6B4A5CB163974A79B","Action":"GetApiKey","Version":"2024-01-01","Service":"ark","Region":"cn-beijing"},"Result":{"ApiKey":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmstY29uc29sZSIsImV4cCI6MTcxODY3NDkyMiwiaWF0IjoxNzE2MTY5MzIyLCJ0IjoidXNlciIsImt2IjoxLCJhaWQiOiIyMTAwNDcyNTU3IiwidWlkIjoiMjc3NjE2MjIiLCJpc19vdXRlcl91c2VyIjp0cnVlLCJyZXNvdXJjZV90eXBlIjoiZW5kcG9pbnQiLCJyZXNvdXJjZV9pZHMiOlsiZXAtMjAyNDA1MTYwMTE0MDEtZzY4cXciXX0.VMNUb8islI8G6g1p0a1mHh3QkAUMoNP6bZIZdfflj4m7UGd8OvGt66tM-aFseqFrraBdTf-Hu_eTkITRqnL4wNy-0p2p-9HZTENC9YnsPj3U3UxoBSApE9L-BfNUbXvEeBIFX3AFgeIeYAiQgN7FB_Lavdl0PxUcP9wwjIPRCE5ZkExRjlhT-7mI82TiyDdlWhCWtr3fKUOccAW63hGeTPcI5-2XV-yvz-E3FdjIxqmIc0b8_0s-LuJP_r8Ae1j1pQ75xUYhGMDrmEdv4xr2yRGZR7-FEe1wNjefMB73MX5D4clUJYzW6BViiIz2cL1Y4loulRX-jQnKKoAsZcX9eQ","ExpiredTime":1718674922}}
     * getApikey: {"ResponseMetadata":{"RequestId":"2024052009420209A6B4A5CB163974A79B","Action":"GetApiKey","Version":"2024-01-01","Service":"ark","Region":"cn-beijing"},"Result":{"ApiKey":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmstY29uc29sZSIsImV4cCI6MTcxODY3NDkyMiwiaWF0IjoxNzE2MTY5MzIyLCJ0IjoidXNlciIsImt2IjoxLCJhaWQiOiIyMTAwNDcyNTU3IiwidWlkIjoiMjc3NjE2MjIiLCJpc19vdXRlcl91c2VyIjp0cnVlLCJyZXNvdXJjZV90eXBlIjoiZW5kcG9pbnQiLCJyZXNvdXJjZV9pZHMiOlsiZXAtMjAyNDA1MTYwMTE0MDEtZzY4cXciXX0.VMNUb8islI8G6g1p0a1mHh3QkAUMoNP6bZIZdfflj4m7UGd8OvGt66tM-aFseqFrraBdTf-Hu_eTkITRqnL4wNy-0p2p-9HZTENC9YnsPj3U3UxoBSApE9L-BfNUbXvEeBIFX3AFgeIeYAiQgN7FB_Lavdl0PxUcP9wwjIPRCE5ZkExRjlhT-7mI82TiyDdlWhCWtr3fKUOccAW63hGeTPcI5-2XV-yvz-E3FdjIxqmIc0b8_0s-LuJP_r8Ae1j1pQ75xUYhGMDrmEdv4xr2yRGZR7-FEe1wNjefMB73MX5D4clUJYzW6BViiIz2cL1Y4loulRX-jQnKKoAsZcX9eQ","ExpiredTime":1718674922}}
     */


    private String signStringEncoder(String source) {
        if (source == null) {
            return null;
        }
        StringBuilder buf = new StringBuilder(source.length());
        ByteBuffer bb = UTF_8.encode(source);
        while (bb.hasRemaining()) {
            int b = bb.get() & 255;
            if (URLENCODER.get(b)) {
                buf.append((char) b);
            } else if (b == 32) {
                buf.append("%20");
            } else {
                buf.append("%");
                char hex1 = CONST_ENCODE.charAt(b >> 4);
                char hex2 = CONST_ENCODE.charAt(b & 15);
                buf.append(hex1);
                buf.append(hex2);
            }
        }

        return buf.toString();
    }

    public static String hashSHA256(byte[] content) throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");

            return bytesToHexString(md.digest(content));
        } catch (Exception e) {
            throw new Exception(
                    "Unable to compute hash while signing request: "
                            + e.getMessage(), e);
        }
    }

    public static byte[] hmacSHA256(byte[] key, String content) throws Exception {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(key, "HmacSHA256"));
            return mac.doFinal(content.getBytes());
        } catch (Exception e) {
            throw new Exception(
                    "Unable to calculate a request signature: "
                            + e.getMessage(), e);
        }
    }

    private byte[] genSigningSecretKeyV4(String secretKey, String date, String region, String service) throws Exception {
        byte[] kDate = hmacSHA256((secretKey).getBytes(), date);
        byte[] kRegion = hmacSHA256(kDate, region);
        byte[] kService = hmacSHA256(kRegion, service);
        return hmacSHA256(kService, "request");
    }

    /**
     * byte[]转16进制字符串
     *
     * @param src
     * @return 中间带空格分割
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return "";
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            if (i == src.length - 1) {
                stringBuilder.append(hv);
            } else {
                stringBuilder.append(hv).append(" ");
            }
        }
        return stringBuilder.toString().toLowerCase().replace(" ","");
    }
}